use v6;

our $JobsCOP is export = %*ENV{'COPROC'} ?? %*ENV{'COPROC'}.Int !! 8;

class Jobs is export {
	has $!cop;
	has @!jobs;
	
	submethod BUILD(Int $cop = $JobsCOP) {
		$!cop = $cop;
		@!jobs = do for 1..$!cop { Any };
	}
	
	multi method add(&func, $res is rw) {
		loop {
			for @!jobs.kv -> $i, $n {
				if $n !=== Any && $n.status != PromiseStatus::Planned {
					@!jobs[$i] = Any;
				}
				if @!jobs[$i] === Any {
					@!jobs[$i] = start { $res = &func() };
					return
				}
			}
			await Promise.anyof(@!jobs)
		}
	}

	multi method add(&func) {
		self.add: &func, $
	}

	method wait_all() {
		await Promise.allof( @!jobs.grep: {
			$_ !=== Any && $_.status == PromiseStatus::Planned
		} );
	}

	method do_all(Jobs:U: @funcs) {
		my \js = Jobs.new;
		my @arr = [];
		for @funcs -> $j {
			@arr.push: $;
			js.add: $j, @arr[*-1];
		}
		js.wait_all;
		@arr
	}
}


sub postfix:<<\>!>> (@funcs) is export {
	Jobs.do_all: @funcs
}

